package com.nondo.dean.auth.provider.impl;


import com.nondo.dean.auth.common.BusinessUtils;
import com.nondo.dean.auth.common.TokenPrincipal;
import com.nondo.dean.auth.common.TokenPrincipalProvider;
import com.nondo.dean.auth.common.bean.MenuItem;
import com.nondo.dean.auth.common.bean.MenuRoleItem;
import com.nondo.dean.auth.common.bean.TreeBean;
import com.nondo.dean.auth.domain.Menu;
import com.nondo.dean.auth.domain.RoleMenuKey;
import com.nondo.dean.auth.provider.MenuManager;
import com.nondo.dean.auth.service.MenuService;
import com.nondo.dean.auth.service.RoleMenuService;
import com.nondo.dean.common.web.Page;
import com.nondo.dean.common.web.Query;
import com.nondo.dean.common.web.View;
import com.nondo.dean.uniqueid.UniqueId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.nondo.dean.auth.common.BusinessUtils.OPERA_ADD;
import static com.nondo.dean.auth.common.TokenPrincipal.PARAMS_SPLIT;

/**
 * @author linfeng
 */
@Service
public class MenuManagerImpl implements MenuManager {

    @Autowired
    private RoleMenuService roleMenuService;
    @Autowired
    private MenuService menuService;
    @Autowired
    TokenPrincipalProvider principalProvider;
    @Autowired
    private UniqueId uniqueId;

    /**
     * 通用菜单保存
     *
     * @param menuItem 菜单传输对象
     */
    private void saveMenu(final MenuItem menuItem) {

        String parentPath = "";
        Menu menu = BusinessUtils.toMenu(menuItem);
        if (menuItem.getParentId() != null) {
            //父菜单不为空，查询出父菜单
            Menu parentMenu = menuService.findByMenuId(menu.getParentId());
            parentPath = parentMenu.getParentIds();
        }
        menu.setParentIds(parentPath + "/" + menu.getName());
        menuService.saveAndUpdateMenu(menu);

        saveChildMenu(menu);

    }

    private void saveChildMenu(Menu parentMenu) {

        List<Menu> childMenus = menuService.findByParentId(parentMenu.getId());
        if (childMenus != null && !childMenus.isEmpty()) {
            for (Menu menu : childMenus) {
                menu.setParentIds(parentMenu.getParentIds() + "/" + menu.getName());
                menuService.saveAndUpdateMenu(menu);

                saveChildMenu(menu);
            }
        }
    }

    @Override
    public View<String> requestMenuRegister(MenuItem menuItem) {

        saveMenu(menuItem);
        if (menuItem.getRoleIds() != null) {
            updateMenuRole(menuItem.getRoleIds(), menuItem.getId());
        }

        return View.ofOk("保存菜单成功");
    }

    @Override
    public View<Menu> requestMenuOne(Long menuId) {
        Menu menu = menuService.findByMenuId(menuId);
        return View.ofOk(menu);
    }

    @Override
    public View<String> requestMenuDelete(Long menuId) {

        List<RoleMenuKey> roleMenuKeyList = roleMenuService.findByMenuId(menuId);
        if (roleMenuKeyList.isEmpty()) {
            menuService.deleteByMenuId(menuId);
        } else {
            return View.ofError("该菜单已经绑定了角色，请先解绑角色");
        }
        return View.ofOk("删除菜单成功");
    }

    @Override
    public View<Void> requestRoleBindMenuRegister(MenuRoleItem menuItem) {

        updateMenuRole(menuItem.getRoleIds(), menuItem.getMenuId());

        return View.ofOk("角色绑定菜单成功");
    }

    /**
     * 保存或删除角色菜单关系
     *
     * @param roleIds 角色集合
     * @param menuId  菜单ID
     */
    private void updateMenuRole(Map<String, List<Long>> roleIds, Long menuId) {
        for (Map.Entry<String, List<Long>> entry : roleIds.entrySet()) {
            if (OPERA_ADD.equals(entry.getKey())) {
                for (Long roleId : entry.getValue()) {
                    roleMenuService.saveRoleMenu(roleId, menuId);
                }
            } else {
                for (Long roleId : entry.getValue()) {
                    roleMenuService.deleteByRoleIdAndMenuId(roleId, menuId);
                }
            }
        }
    }

    @Override
    public View<Void> requestRoleUnBindMenuRegister(MenuRoleItem menuItem) {

        updateMenuRole(menuItem.getRoleIds(), menuItem.getMenuId());
        return View.ofOk("角色解绑菜单成功");
    }

    @Override
    public View<Void> requestMultMenuRegister(List<MenuItem> menus) {
        for (MenuItem menuItem : menus) {
            saveMenu(menuItem);
            updateMenuRole(menuItem.getRoleIds(), menuItem.getId());
        }
        return View.ofOk("菜单注册成功");
    }

    @Override
    public View<List<TreeBean>> requestMenuTreeOfAll() {

        List<TreeBean> menuTreeList = new ArrayList<>();
        List<Menu> menus = menuService.findAll();

        initRootMenu(menuTreeList, menus);

        return View.ofOk("树形菜单", menuTreeList);
    }

    @Override
    public View<Page<Menu>> requestQuery(Query<MenuItem> item) {
        Query<Menu> menuQuery = new Query<>();
        menuQuery.setPage(item.getPage());
        menuQuery.setSize(item.getSize());
        menuQuery.setData(BusinessUtils.toMenu(item.getData()));

        Page<Menu> officePage = menuService.findPage(menuQuery);
        return View.ofOk(officePage);
    }

    @Override
    public View<List<TreeBean>> requestMenuTreeOfUser() {


        TokenPrincipal principal = principalProvider.getTokenPrincipal();
        if (principal == null) {
            return View.ofError("用户没有登录，请登录");
        }

        List<TreeBean> menuTreeList = new ArrayList<>();
        String roles = principal.getRoles();
        if (roles != null) {

            List<Long> roleIds = Arrays.asList(roles.split(PARAMS_SPLIT)).parallelStream().map(Long::valueOf).collect(Collectors.toList());
            List<RoleMenuKey> roleMenuKeyList = roleMenuService.findByRoleIds(roleIds);
            List<Long> menuIdList = roleMenuKeyList.stream().map(RoleMenuKey::getMenuId).collect(Collectors.toList());

            List<Menu> menus = menuService.findAll();
            menus = menus.stream().filter(item -> menuIdList.contains(item.getId())).collect(Collectors.toList());
            initRootMenu(menuTreeList, menus);
        }

        return View.ofOk("树形菜单", menuTreeList);

    }

    /**
     * 取出顶级菜单
     *
     * @param menuTreeList 菜单结果集合
     * @param menus        菜单集合
     */
    private void initRootMenu(List<TreeBean> menuTreeList, List<Menu> menus) {
        Iterator<Menu> iter = menus.iterator();
        while (iter.hasNext()) {
            Menu menu = iter.next();
            if (menu.getParentId() == null) {
                menuTreeList.add(new TreeBean(menu.getName(), menu.getName(), menu.getId() + "", menu.getId() + ""));
                iter.remove();
            }
        }
        initMenuTree(menuTreeList, menus);
    }

    /**
     * 转换菜单为树形菜单
     *
     * @param menuTreeList 菜单结果集合
     * @param menus        菜单集合
     */
    private void initMenuTree(List<TreeBean> menuTreeList, List<Menu> menus) {

        List<TreeBean> childMenuTreeList = new ArrayList<>();
        TreeBean treeBean;
        for (TreeBean bean : menuTreeList) {
            Iterator<Menu> iter = menus.iterator();
            while (iter.hasNext()) {
                Menu menu = iter.next();
                if (bean.getKey().equals(menu.getParentId() + "")) {
                    treeBean = new TreeBean(menu.getName(), menu.getName(), menu.getId() + "", menu.getId() + "");
                    bean.getChildren().add(treeBean);
                    childMenuTreeList.add(treeBean);
                    iter.remove();
                }
            }
        }
        if (!childMenuTreeList.isEmpty()) {
            initMenuTree(childMenuTreeList, menus);
        }

    }

}
